package com.elitel.frame.base.component.quartz;

import com.elitel.common.elasticSearch.ESClient;
import com.elitel.common.ftp.FtpDocumentInfo;
import com.elitel.common.ftp.FtpUtil;
import com.elitel.common.tika.TikaUtil;
import com.elitel.frame.base.component.exportprojectdata.ElasticSerachInfo;
import com.elitel.frame.base.service.SysDocumentService;
import com.elitel.frame.main.entity.SysDocument;
import com.elitel.frame.main.entity.vo.DocumentESIndexVo;
import net.sf.json.JSONObject;
import org.apache.commons.lang.StringUtils;
import org.quartz.Job;
import org.quartz.JobDetail;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.beans.factory.annotation.Autowired;

import java.io.File;
import java.lang.reflect.Field;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * 创建全文检索Job任务，项目非结构化文档定时更新elasticsearch索引库
 * created by guoyanfei on 2018/4/19
 */
public class SearchDocumentQuartz implements Job {
    @Autowired
    private ElasticSerachInfo elasticSerachInfo;
    @Autowired
    private SysDocumentService sysDocumentService;

    /**
     * 定时执行任务操作
     * created by guoyanfei on 2018/04/19
     *
     * @param context
     * @throws JobExecutionException
     */
    @Override
    public  void execute(JobExecutionContext context) {
        JobDetail jobDetail = context.getJobDetail();
        //服务ID
        String serviceId = jobDetail.getJobDataMap().getString("serviceId");
        if (StringUtils.isEmpty(serviceId)) {
            return;
        }

        //项目非结构化文档配置信息
        SysDocument sysDocument = sysDocumentService.selectInfoByserviceId(serviceId);
        if (sysDocument == null) {
            return;
        }

        //1、设置项目非结构化文档状态为正在更新索引库
        SysDocument beginsysDocument = new SysDocument();
        beginsysDocument.setGuid(sysDocument.getGuid());
        beginsysDocument.setStatus(2);
        sysDocumentService.updateSysDocument(beginsysDocument);

        String indexname = sysDocument.getGuid();
        String indexType = sysDocument.getIndextype();
        ESClient esClient = new ESClient(elasticSerachInfo.address, elasticSerachInfo.port, elasticSerachInfo.clustername);

        //根据数据来源途径获取文档信息，并存入documentInfoList
        List<FtpDocumentInfo> documentInfoList = new ArrayList<>();
        Integer docsource = sysDocument.getDocsource();
        if (docsource.equals(1)) {
            //获取本地文档信息
            documentInfoList = getlocalDocInfo(documentInfoList, sysDocument.getDocpath());
        } else if (docsource.equals(2)) {
            //获取FTP服务器信息
            FtpUtil ftpUtil = new FtpUtil(sysDocument.getFtphost(), sysDocument.getFtpuser(),
                    sysDocument.getFtppass(), sysDocument.getFtpport());
            documentInfoList = ftpUtil.getFtpfile(documentInfoList, sysDocument.getDocpath());
            ftpUtil.closeFtpClient();
        }

        //While循环遍历documentInfoList，批次检查更新
        int start = 0;
        while (start <= documentInfoList.size()) {
            List<DocumentESIndexVo> document = new ArrayList<>();
            //判断索引是否存在
            Boolean isExist = esClient.indexExists(indexname);
            if (isExist) {
                //分批次获取目标路径文件信息，每批次100条
                document = getDocumentInfo(docsource, documentInfoList, start);
                //更新索引中当前批次文档数据
                updateESIndex(sysDocument, document, esClient, indexname, indexType);
            } else {
                //新增索引库
                esClient.createIndexUseIK(indexname, indexType, new DocumentESIndexVo());
            }
            start += document.size();
            if (start == documentInfoList.size()) {
                break;
            }
        }

        //3、设置项目非结构化文档状态为正常
        SysDocument endsysDocument = new SysDocument();
        endsysDocument.setGuid(sysDocument.getGuid());
        endsysDocument.setStatus(1);
        sysDocumentService.updateSysDocument(endsysDocument);

        System.out.println("任务调度更新完成-服务编码：" + serviceId + ",时间：" + new Date());
        esClient.closeClient();
    }

    /**
     * 获取文档信息，并根据isGetText判断是否获取文档内容
     *
     * @return
     */
    private List<DocumentESIndexVo> getDocumentInfo(Integer docsource, List<FtpDocumentInfo> documentInfoList, int start) {
        Integer updatefetch = elasticSerachInfo.updatefetch;
        List<DocumentESIndexVo> documentESIndexVos = new ArrayList<>();

        if (documentInfoList != null && documentInfoList.size() > 0) {
            int count = 0;
            for (int i = start; i < documentInfoList.size(); i++) {
                FtpDocumentInfo fdi = documentInfoList.get(i);
                String fileContext = "";
                DocumentESIndexVo documentESIndexVo = new DocumentESIndexVo();
                if (docsource.equals(1)) {
                    //本地文档信息
                    documentESIndexVo.setDocSource(1);
                    documentESIndexVo.setDocSourceDescribe("本地文件");
                } else if (docsource.equals(2)) {
                    //FTP服务器信息
                    documentESIndexVo.setDocSource(2);
                    documentESIndexVo.setDocSourceDescribe("FTP服务器");
                }
                documentESIndexVo.setFilename(fdi.getFilename());
                documentESIndexVo.setDocpath(fdi.getFiledirectory());
                documentESIndexVo.setFilesize(fdi.getFilesize());
                documentESIndexVo.setFilecontext(fileContext.replace(" ", ""));
                documentESIndexVo.setModifytime(fdi.getModifytime());
                documentESIndexVos.add(documentESIndexVo);
                count++;

                if (count % updatefetch == 0) {
                    return documentESIndexVos;
                }
            }
        }
        return documentESIndexVos;
    }

    /**
     * 获取文档内容
     *
     * @param sysDocument
     * @return
     */
    private List<DocumentESIndexVo> getFileContext(SysDocument sysDocument, HashSet<DocumentESIndexVo> desvos,String indexname) {
        List<DocumentESIndexVo> esDocs = new ArrayList<>();
        if (sysDocument.getDocsource().equals(1)) {
            //获取本地文件内容
            for (DocumentESIndexVo desvo : desvos) {
                String fileContext = TikaUtil.getContextParser(desvo.getDocpath() + "\\" + desvo.getFilename());
                desvo.setFilecontext(fileContext);
                esDocs.add(desvo);
            }
        } else if (sysDocument.getDocsource().equals(2)) {
            //获取FTP文件内容
            FtpUtil ftpUtil = new FtpUtil(sysDocument.getFtphost(), sysDocument.getFtpuser(),
                    sysDocument.getFtppass(), sysDocument.getFtpport());
            String localpath = "main-frame-file/estemp"+indexname;
            File uploadRootDir = new File(localpath);
            if (!uploadRootDir.exists()) {
                uploadRootDir.mkdirs();
            }
            for (DocumentESIndexVo desvo : desvos) {
                String filename = desvo.getFilename();
                boolean isdown = ftpUtil.downloadFtpFile(desvo.getDocpath(), localpath, filename);
                if (isdown) {
                    String fileContext = TikaUtil.getContextParser(localpath + "\\" + filename);
                    desvo.setFilecontext(fileContext);
                    esDocs.add(desvo);
                } else {
                    System.out.println("文件下载失败:" + filename);
                }
            }
            //清空本地临时文件夹
            boolean isdelte = DeleteUtil.DeleteFolder(localpath);
            if (isdelte) {
                System.out.println("删除FTP更新临时文件");
            }
            ftpUtil.closeFtpClient();
        }
        return esDocs;
    }

    /**
     * 把文档内容更新到索引库
     * created by guoyanfei on 2018/04/19
     *
     * @param documentESIndexVos 文档内容集合
     * @param indexname          索引库名称
     * @param indexType          索引库类型
     */
    private void updateESIndex(SysDocument sysDocument, List<DocumentESIndexVo> documentESIndexVos, ESClient esClient, String indexname, String indexType) {
        try {
            HashSet<DocumentESIndexVo> desvos = new HashSet<>();
            //遍历目标路径各文档信息
            for (DocumentESIndexVo desvo : documentESIndexVos) {
                String conditions = "docpath:" + desvo.getDocpath() + "|filename:" + desvo.getFilename();

                //获取该文档id
                List<String> ids = esClient.searchDocumentId(indexname, indexType, 1, 1, conditions);

                //如果elasticsearch索引库中存在该文档，更新文档
                if (ids != null && ids.size() > 0) {
                    String docinfo = esClient.getDatabyId(indexname, indexType, ids.get(0));
                    JSONObject jsonObject = JSONObject.fromObject(docinfo);
                    Map<String, Object> jsonmap = (Map<String, Object>) jsonObject;
                    //获取该文档修改时间
                    String modifytime = jsonmap.get("modifytime").toString();

                    //文档最后更新时间不同，更新该文档
                    if (!modifytime.equals(desvo.getModifytime())) {
//                        System.out.println("++++++++++++" + indexname + ":modifytime开始更新索引信息" + desvo.getFilename() + "++++++++++++++++++");
                        desvo.setId(ids.get(0));
                        desvos.add(desvo);
                    }
                } else {//elasticsearch索引库中不存在该文档，新增文档入索引库
//                    System.out.println("++++++++++++" + indexname + ":new开始更新索引信息" + desvo.getFilename() + "++++++++++++++++++");
                    desvos.add(desvo);
                }
            }
            //如果有文档需要更新，则获取文档信息并更新入索引
            if (!desvos.isEmpty()) {
                List<DocumentESIndexVo> devos = getFileContext(sysDocument, desvos,indexname);
                for (DocumentESIndexVo devo : devos) {
                    Map<String, Object> map = objectToMap(devo);
                    esClient.bulkUpdateData(indexname, indexType, devo.getId(), map);
                }
                esClient.flushBulk();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 实体对象转换成Map<String,Object>对象
     * created by guoyanfei on 2018/04/19
     *
     * @param obj 实体对象
     * @return Map<String, Object>对象
     */
    private Map<String, Object> objectToMap(Object obj) {
        Map<String, Object> map = new HashMap<>();
        if (obj == null) {
            return map;
        }

        Class cla = obj.getClass();
        Field[] fields = cla.getDeclaredFields();
        try {
            for (Field field : fields) {
                field.setAccessible(true);
                map.put(field.getName(), field.get(obj));
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        return map;
    }

    /**
     * 获取本地文档信息
     * created by guoyanfei on 2018/04/23
     *
     * @param localPath 本地文档路径
     * @return FtpDocumentInfo 实体list集合
     */
    private List<FtpDocumentInfo> getlocalDocInfo(List<FtpDocumentInfo> ftpDocumentInfos, String localPath) {
        File file = new File(localPath);
        File[] files = file.listFiles();
        if (files != null && files.length > 0) {
            for (File filevo : files) {
                if (filevo.isDirectory()) {
                    getlocalDocInfo(ftpDocumentInfos, localPath + "/" + filevo.getName());
                }
                if (filevo.isFile()) {
                    FtpDocumentInfo ftpDocumentInfo = new FtpDocumentInfo();
                    ftpDocumentInfo.setFilename(filevo.getName());
                    ftpDocumentInfo.setFiledirectory(localPath);
                    ftpDocumentInfo.setFilesize(filevo.length());

                    SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                    Calendar cal = Calendar.getInstance();
                    long time = filevo.lastModified();
                    cal.setTimeInMillis(time);

                    ftpDocumentInfo.setModifytime(formatter.format(cal.getTime()));
                    ftpDocumentInfos.add(ftpDocumentInfo);

                }
            }
        }
        return ftpDocumentInfos;
    }
}
